import { App, Config, Inject, Provide } from '@midwayjs/decorator'
import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web'
import { CacheManager } from '@midwayjs/cache'
import { Application, Context } from 'egg'

import { MESSAGE } from '../constants/code'

@Provide()
export class jwtAuthMiddleware implements IWebMiddleware {

  @App()
  app: Application

  @Inject()
  cache: CacheManager

  @Config('jwt')
  jwtConfig: any

  resolve() {
    return async (ctx: Context, next: IMidwayWebNext) => {
      const authorization = ctx.get('authorization')

      try {

        if (authorization) {
          const [scheme, token] = authorization.split(' ')

          if (!/^Bearer$/i.test(scheme)) {
            ctx.throw(401, ctx.__(MESSAGE.TOKEN_INVALID))
          }

          if (!token) {
            ctx.throw(401, ctx.__(MESSAGE.MISSING_TOKEN))
          }

          if (!ctx.state) {
            ctx.state = {}
          }

          try {
            const decoded = await this.app.jwt.verify(token)

            if (decoded) {
              const tokenExpired = await this.cache.get(decoded['id'])

              if (tokenExpired) {
                ctx.throw(401, ctx.__(MESSAGE.TOKEN_INVALID))
              }

              if (decoded['isRefresh']) {
                ctx.throw(401, ctx.__(MESSAGE.TOKEN_INVALID))
              }

              ctx.state = decoded
            }
          } catch (err) {
            ctx.throw(401, ctx.__(MESSAGE.TOKEN_EXPIRED))
          }
        }

      } catch (err) {
        ctx.status = err.status
        ctx.body = {
          message: err.message
        }
      }

      await next()
    }
  }
}
